#ifndef __MIXINBASE_HH__
#define __MIXINBASE_HH__

#include <boost/scoped_ptr.hpp>

#include "Common/Meta/If.hh"
#include "Common/Meta/TypesEqual.hh"

namespace Common
{

namespace Patterns
{

/**
 * @struct Mixins class acts like a container for all mixins, and it provides
 * multi inheritance for all mixins.
 */
template< typename... T >
struct Mixins : public T...
{
};

/**
 * @struct MixinsSize help struct to compute at compile time size of
 * mixins held inside Mixins container.
 */
template< template< typename > class... T >
struct MixinsSize;

/**
 * @struct MixinsSize recurse specialization for compile time size counting.
 */
template< template< typename > class H, template< typename > class... T >
struct MixinsSize< H, T... >
{
    enum{ value = MixinsSize< T... >::value + 1 };
};

/**
 * @struct MixinsSize and end of recursion.
 */
template<>
struct MixinsSize<>
{
    enum{ value = 0 };
};

/**
 * @struct MixinId class to compute an id of a mixin to have one and only mapping
 * inside each compilation: id -> mixin type. Calculates id from mixin type at compile
 * time.
 */
template< int counter
        , typename BASE
        , typename KEY
        , template< typename > class... T
        >
struct MixinId;

/**
 * @struct MixinId class to compute an id of a mixin to have one and only mapping
 * inside each compilation: id -> mixin type. Calculates id from mixin type at compile
 * time.
 */
template< int counter
        , typename BASE
        , typename KEY
        , template< typename > class HEAD
        , template< typename > class... TAIL >
struct MixinId< counter, BASE, KEY, HEAD, TAIL... >
{
    typedef typename Meta::If<
                        MixinId< counter, BASE, KEY >
                      , MixinId< counter + 1, BASE, KEY, TAIL... >
                      , Meta::TypesEqual< KEY, HEAD< BASE > >::value
                        >::Value Value;

    enum{ value = counter };
};

/**
 * @struct MixinId Recursion definition
 */
template< int counter
        , typename BASE
        , typename KEY >
struct MixinId< counter, BASE, KEY >
{
    enum{ value = counter };
};

/**
 * @struct MixinId End of recursion.
 */
template< int typeId
        , typename BASE
        , template< typename > class... LIST >
struct MixinType;

/**
 * @struct MixinType Class used to get the mixin type by its id its behaviour is
 * oposite to MixinId struct.
 */
template< int typeId
        , typename BASE
        , template< typename > class HEAD
        , template< typename > class... TAIL >
struct MixinType< typeId, BASE, HEAD, TAIL... >
{
    typedef typename MixinType< typeId - 1, BASE, TAIL... >::Value Value;
};

/**
 * @struct MixinType End of recursion.
 */
template< typename BASE
        , template< typename > class HEAD >
struct MixinType< 0, BASE, HEAD >
{
    typedef HEAD< BASE > Value;
};

/**
 * @struct MixinTypes Encapsulates the mixin types managament.
 */
template< template< typename > class... T >
struct MixinTypes
{
    /// static value for mixin collection size
    enum{ size = MixinsSize< T... >::value };

    /**
     * @struct Wrapper for mixinid calculation.
     */
    template< typename BASE, typename KEY >
    struct GetMixinId
    {
        enum{ id = MixinId< 0, BASE, KEY, T... >::Value::value };
    };

    /**
     * @struct Wrapper for get mixin type operation
     */
    template< typename BASE, int typeId >
    struct GetTypeAtId
    {
        typedef typename MixinType< typeId, BASE, T... >::Value Value;
    };

    /**
     * @struct TypesTable class handles to mixin types convertion from a base class
     * it uses static size table of pointers and fills it with data just with the first
     * use. It is completly transparant if it uses "template magic" or normal dynamic_cast.
     * @note Difference will be noticable at runtime ;)
     */
    template< typename BASE >
    struct TypesTable
    {
        /**
         * @brief Default ctor.
         * Just sets the initialized flag to false
         */
        TypesTable( void ) : iInitialized( false )
        {
        }

        /**
         * @brief Initialization of the table. It is done here because ctor
         * would make us to dynamicly allocate this object which would cost
         * us extra time for new/deletes.
         */
        void initialize( BASE* aBasePtr )
        {
            TypesGenerator< size - 1, BASE, T... >( aBasePtr, iPtrs );
            iInitialized = true;
        }

        /**
         * @brief operator[]
         * @returns Address of a wanted mixin.
         * @todo some address checking may be performed here, but since
         * id is calculated upon static type i don't see reason to do that.
         */
        intptr_t operator[]( unsigned iIndex ) const
        {
            return iPtrs[ iIndex ];
        }

        /**
         * @brief Operator !
         * @returns true if table was initialized false otherway
         */
        bool operator!( void ) const
        {
            return !iInitialized;
        }
        
    private:
        /// flag that determins if table was initialized
        bool     iInitialized;
        /// table for pointers
        intptr_t iPtrs[ size ];
    };

    /**
     * @struct TypesGenerator help class to calculate adresses of mixins.
     */
    template< int id, typename BASE, template < typename > class... LIST >
    struct TypesGenerator;
            
    /**
     * @struct TypesGenerator help class to calculate adresses of mixins.
     * @brief Recurse version.
     */
    template< int id,
              typename BASE, template < typename > class HEAD,
              template < typename > class... TAIL >
    struct TypesGenerator< id, BASE, HEAD, TAIL... >
    {
        TypesGenerator( BASE* aBasePtr, intptr_t address[] )
        {
            address[ size - 1 - id ] = ( intptr_t ) dynamic_cast< HEAD< BASE >* >( aBasePtr );
            TypesGenerator< id - 1, BASE, TAIL... >( aBasePtr, address );
        }
    };

    /**
     * @struct TypesGenerator help class to calculate adresses of mixins.
     * @brief End of recursion.
     */
    template< typename BASE, template < typename > class HEAD >
    struct TypesGenerator< 0, BASE, HEAD >
    {
        TypesGenerator( BASE* aBasePtr, intptr_t address[] )
        {
            address[ size - 1 ] = ( intptr_t ) dynamic_cast< HEAD< BASE >* >( aBasePtr );
        }
    };
};


} // namespace Patterns
} // namespace Common
#endif